// pngparser.cpp
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <string.h>
#include "png.h"
#include "zlib.h"

using namespace std;

//http://www.sucaitianxia.com/d/file/20120415/81e25f93ec0555c3bd2e44ddaebd4619.png
bool httpdownloadMethod1(const string &url , const string &pngFileName)
{
    if (url.rfind("/") == string::npos || url.find(".png") == string::npos
            || pngFileName.find(".png") == string::npos)
    {
        cout << "not png file" << endl;
        return false;
    }
    string downloadScript("wget -O ");
    downloadScript += pngFileName;
    downloadScript += " " + url;
    int status = system(downloadScript.c_str());
    //cout << " http download =  " << downloadScript  << " " << status << endl;
    if (-1 == status)
    {
        cout << "system error " << endl;
        return false;
    }
    downloadScript.clear();
    return true;
}

bool convertToRectangle(string const &src,  string const &mask, unsigned int flag)
{
    // 前边几句是扯淡，初始化各种结构
    FILE *file = fopen(src.c_str(), "rb");
    if (NULL == file)
    {
        return false;
    }

    FILE *fileMask = fopen(mask.c_str(), "rb");
    if (NULL == fileMask)
    {
        return false;
    }
    // 初始化 源图像结构体
    png_structp PngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
    if (!PngPtr)
    {
        cout << "[write_png_file] png_create_write_struct failed" << endl;
        return false;
    }
    png_infop InfoPtr = png_create_info_struct(PngPtr);
    if (!InfoPtr)
    {
        cout << "[write_png_file] png_create_write_struct failed" << endl;
        return false;
    }
    if (setjmp(png_jmpbuf(PngPtr)))
    {
        cout << "[write_png_file] Error during init_io" << endl;
        return false;
    }
    png_init_io(PngPtr, file);
    // 读文件
    png_read_png(PngPtr, InfoPtr, PNG_TRANSFORM_EXPAND, 0);
    // 得到文件的宽高色深
    int m_width = png_get_image_width(PngPtr, InfoPtr);
    int m_height = png_get_image_height(PngPtr, InfoPtr);
    int bit_depth = png_get_bit_depth(PngPtr, InfoPtr);
    int color_type = png_get_color_type(PngPtr, InfoPtr);
    // 申请内存
    //int size = m_height * m_width * flag;
    //unsigned char* rgba = new unsigned char[size];


    // 初始化 模板图像结构体
    png_structp PngPtrMask = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
    if (!PngPtrMask)
    {
        cout << "[write_png_file] png_create_write_struct failed" << endl;
        return false;
    }
    png_infop InfoPtrMask = png_create_info_struct(PngPtrMask);
    if (!InfoPtrMask)
    {
        cout << "[write_png_file] png_create_info_struct failed" << endl;
        return false;
    }
    if (setjmp(png_jmpbuf(PngPtrMask)))
    {
        cout << "[write_png_file] Error during init_io" << endl;
        return false;
    }
    png_init_io(PngPtrMask, fileMask);
    // 读文件
    png_read_png(PngPtrMask, InfoPtrMask, PNG_TRANSFORM_EXPAND, 0);
    // 得到文件的宽高色深
    int m_widthmask = png_get_image_width(PngPtrMask, InfoPtrMask);
    int m_heightmask = png_get_image_height(PngPtrMask, InfoPtrMask);
    int color_typemask = png_get_color_type(PngPtrMask, InfoPtrMask);
    // 申请内存
    //int sizemask = m_heightmask * m_heightmask * flag;
    //unsigned char* rgbamask = new unsigned char[sizemask];

    int pos = 0;
    // row_pointers里边就是rgba数据了
    png_bytep *row_pointersSrc = png_get_rows(PngPtr, InfoPtr);


    png_bytep *row_pointersmask = png_get_rows(PngPtrMask, InfoPtrMask);


    // 拷贝！！注意，如果读取的png有A通道，就要4位4位的读。还有就是注意字节对其的问题
    for (int i = 0; i < m_height; i++)
    {
        for (int j = 0; j < (flag * m_width); j += flag)
        {
            row_pointersSrc[i][j]     = row_pointersSrc[i][j] | row_pointersmask[i][j];
            row_pointersSrc[i][j + 1] = row_pointersSrc[i][j + 1] | row_pointersmask[i][j + 1];
            row_pointersSrc[i][j + 2] = row_pointersSrc[i][j + 2] | row_pointersmask[i][j + 2];
            row_pointersSrc[i][j + 3] = row_pointersSrc[i][j + 3] & row_pointersmask[i][j + 3];

            /*
            rgba[pos++] = row_pointers[i][j];      //    red
            rgba[pos++] = row_pointers[i][j + 1];  //    green
            rgba[pos++] = row_pointers[i][j + 2];   //   blue
            rgba[pos++] = row_pointers[i][j + 3];   //   alpha
            */
        }
    }


    int j, i, temp;
    png_structp png_ptr;
    png_infop info_ptr;
    png_bytep *row_pointers;
    /* create file */
    fclose(file);
    FILE *fp = fopen(src.c_str(), "wb");
    if (!fp)
    {
        return false;
    }
    /* initialize stuff */
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
    {
        cout << "[write_png_file] png_create_write_struct failed" << endl;
        return false;
    }
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        cout << "[write_png_file] png_create_info_struct failed" << endl;
        return false;
    }
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        cout << "[write_png_file] Error during init_io" << endl;
        return false;
    }
    png_init_io(png_ptr, fp);


    /* write header */
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        cout << "[write_png_file] Error during writing header" << endl;
        return false;
    }
    /* 判断要写入至文件的图片数据是否有透明度，来选择色彩类型 */
    color_type = PNG_COLOR_TYPE_RGB_ALPHA;

    png_set_IHDR(png_ptr, info_ptr, m_width, m_height,
                 bit_depth, color_type, PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

    png_write_info(png_ptr, info_ptr);

    /* write bytes */
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        printf("[write_png_file] Error during writing bytes");
        return false;
    }
    temp = (flag * m_width);
    row_pointers = (png_bytep *)malloc(m_height * sizeof(png_bytep));
    for (i = 0; i < m_height; i++)
    {
        row_pointers[i] = (png_bytep)malloc(sizeof(unsigned char) * temp);
        for (j = 0; j < temp; j += flag)
        {
            row_pointers[i][j]   = row_pointersSrc[i][j]; // red
            row_pointers[i][j + 1] = row_pointersSrc[i][j + 1]; // green
            row_pointers[i][j + 2] = row_pointersSrc[i][j + 2]; // blue
            row_pointers[i][j + 3] = row_pointersSrc[i][j + 3]; // alpha
        }
    }

    png_write_image(png_ptr, row_pointers);

    /* end write */
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        printf("[write_png_file] Error during end of write");
        return false;
    }
    png_write_end(png_ptr, NULL);

    /* cleanup heap allocation */
    for (j = 0; j < m_height; j++)
    {
        free(row_pointers[j]);
    }
    free(row_pointers);
    png_destroy_read_struct(&PngPtr, &InfoPtr, 0);
    png_destroy_read_struct(&PngPtrMask, &InfoPtrMask, 0);
    fclose(fp);
    fclose(fileMask);
    return true;
}

bool copyPngToDst(const string &strSrc, const string &strDst)
{
	if(strDst.find(".png") == string::npos)
	{
		cout << "saved file error" << endl;
		return false;
	}
    FILE* finput = fopen(strSrc.c_str(), "r");
    if(NULL == finput)
    {
        cout << "source image error" << endl;
        return false;
    }
    fclose(finput);
    string strCmd = "cat " + strSrc + " >> " + strDst;
	cout << "copy cmd = " << strCmd << endl;
	if (-1 == system(strCmd.c_str()))
    {
		cout << strCmd <<"error" << endl;
        return false;
    }
    FILE* ftest = fopen(strDst.c_str(), "r");
    if(NULL == ftest)
    {
        cout << "dst file error" << endl;
        return false;
    }
    fclose(ftest);
    return true;
}



int main(int argc, char *argv[])
{

    if (3 != argc)
    {
        cout << "arg num error!" << endl;
        return -1;

    }
    unsigned int flag = 4;
    png_image image;
    string strSaveImagepath(argv[2]);
    string strMaskfile("RGBAmask_57_radian12.png");
    memset(&image, 0, (sizeof image));
    image.version = PNG_IMAGE_VERSION;
    string strSource(argv[1]);
    if (strSource.find("http://") == string::npos)
    {
        if (false == copyPngToDst(strSource, strSaveImagepath))
        {
            return -1;
        }
    }
    else
    {
        if (false == httpdownloadMethod1(strSource, strSaveImagepath))
        {
            cout << "http download error..." << endl;
            return -1;
        }
    }

    if (png_image_begin_read_from_file(&image, strSaveImagepath.c_str()))  //argv[1]
    {
        cout << "image width and height : " << image.width << "  " << image.height << " "  <<  endl;
        if ( (image.width != 57 || image.height != 57) && (image.width != 72 || image.height != 72)  )
        {
            cout << "不是标准的 57* 57 72*72 像素点" << endl;
            return -1;
        }
        if (72 == image.width )
        {
            strMaskfile = "RGBAmask_72_radian12.png";
        }
        png_bytep buffer;
        if (image.format == PNG_FORMAT_RGBA)
        {
            cout << "It's RGB+ Alpha Channel 32 deep bits " << endl;
            //return -1;
        }
        else
        {
            image.format = PNG_FORMAT_RGBA;
            cout << "It's not RGB+ Alpha Channel 32 deep bits " << endl;
            buffer = (png_bytep)malloc(PNG_IMAGE_SIZE(image));
            if (buffer != NULL && png_image_finish_read(&image, NULL/*background*/, buffer, 0/*row_stride*/, NULL/*colormap*/))
            {
                if (png_image_write_to_file(&image, strSaveImagepath.c_str(), 0/*convert_to_8bit*/, buffer, 0/*row_stride*/, NULL/*colormap*/))
                {
                    cout << "complete the convert to 32 bit " << endl;
                }
            }
            else
            {
                if (buffer == NULL)
                {
                    png_image_free(&image);
                }
                else
                {
                    free(buffer);
                    buffer = NULL;
                }
            }
        }
    }
    else
    {
        cout << "it's not png style..." << endl;
        if (0 == remove(strSaveImagepath.c_str()))
        {
            cout << " delete the wrong file...." << endl;
        }
        return -1;
    }
    return convertToRectangle( strSaveImagepath, strMaskfile, 4);  //只针对 PGB + alpha通道处理
}

